package com.jl15988.simpletools.system.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.jl15988.simpletools.common.exception.BusinessException;
import com.jl15988.simpletools.system.domain.dto.MenuDTO;
import com.jl15988.simpletools.system.domain.dto.MenuQueryDTO;
import com.jl15988.simpletools.system.domain.entity.Menu;
import com.jl15988.simpletools.system.mapper.MenuMapper;
import com.jl15988.simpletools.system.mapper.RoleMenuMapper;
import com.jl15988.simpletools.system.service.MenuService;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 菜单服务实现类
 *
 * @author jl15988
 */
@Service
public class MenuServiceImpl extends ServiceImpl<MenuMapper, Menu> implements MenuService {

    @Autowired
    private MenuMapper menuMapper;

    @Autowired
    private RoleMenuMapper roleMenuMapper;

    @Override
    public List<Menu> getMenuList(MenuQueryDTO query) {
        LambdaQueryWrapper<Menu> wrapper = new LambdaQueryWrapper<>();
        // 根据菜单名称模糊查询
        if (StringUtils.hasText(query.getName())) {
            wrapper.like(Menu::getName, query.getName());
        }
        // 根据菜单类型查询
        if (query.getType() != null) {
            wrapper.eq(Menu::getType, query.getType());
        }
        // 根据是否显示查询
        if (query.getVisible() != null) {
            wrapper.eq(Menu::getVisible, query.getVisible());
        }
        // 按照父级ID和排序字段排序
        wrapper.orderByAsc(Menu::getParentId).orderByAsc(Menu::getSort);
        return menuMapper.selectList(wrapper);
    }

    @Override
    public List<MenuDTO> getMenuTree(MenuQueryDTO query) {
        // 获取菜单列表
        List<Menu> menuList = getMenuList(query);
        // 转换为DTO
        List<MenuDTO> menuDTOList = menuList.stream().map(this::convertToDTO).collect(Collectors.toList());
        // 构建菜单树
        return buildMenuTree(menuDTOList);
    }

    @Override
    public MenuDTO getMenuDetail(Long id) {
        Menu menu = menuMapper.selectById(id);
        if (menu == null) {
            throw new BusinessException("菜单不存在");
        }
        return convertToDTO(menu);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Long createMenu(MenuDTO menuDTO) {
        // 检查父级菜单是否存在
        if (menuDTO.getParentId() != null && menuDTO.getParentId() != 0) {
            Menu parentMenu = menuMapper.selectById(menuDTO.getParentId());
            if (parentMenu == null) {
                throw new BusinessException("父级菜单不存在");
            }
        }

        // 检查菜单名称是否重复
        LambdaQueryWrapper<Menu> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(Menu::getName, menuDTO.getName())
                .eq(Menu::getParentId, menuDTO.getParentId() != null ? menuDTO.getParentId() : 0);
        if (menuMapper.selectCount(wrapper) > 0) {
            throw new BusinessException("同级菜单名称已存在");
        }

        // 创建菜单
        Menu menu = new Menu();
        BeanUtils.copyProperties(menuDTO, menu);
        // 设置默认值
        if (menu.getParentId() == null) {
            menu.setParentId(0L);
        }
        if (menu.getSort() == null) {
            menu.setSort(0);
        }
        if (menu.getVisible() == null) {
            menu.setVisible(1);
        }
        if (menu.getKeepAlive() == null) {
            menu.setKeepAlive(0);
        }
        if (menu.getExternal() == null) {
            menu.setExternal(0);
        }
        menu.setCreatedAt(LocalDateTime.now());
        menu.setUpdatedAt(LocalDateTime.now());

        menuMapper.insert(menu);
        return menu.getId();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean updateMenu(MenuDTO menuDTO) {
        // 检查菜单是否存在
        Menu existMenu = menuMapper.selectById(menuDTO.getId());
        if (existMenu == null) {
            throw new BusinessException("菜单不存在");
        }

        // 检查父级菜单是否存在
        if (menuDTO.getParentId() != null && menuDTO.getParentId() != 0) {
            Menu parentMenu = menuMapper.selectById(menuDTO.getParentId());
            if (parentMenu == null) {
                throw new BusinessException("父级菜单不存在");
            }
            // 不能将自己设为自己的父级
            if (menuDTO.getId().equals(menuDTO.getParentId())) {
                throw new BusinessException("不能将自己设为自己的父级");
            }
            // 不能将自己的子菜单设为自己的父级
            List<Long> childIds = getChildMenuIds(menuDTO.getId());
            if (childIds.contains(menuDTO.getParentId())) {
                throw new BusinessException("不能将自己的子菜单设为自己的父级");
            }
        }

        // 检查菜单名称是否重复
        LambdaQueryWrapper<Menu> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(Menu::getName, menuDTO.getName())
                .eq(Menu::getParentId, menuDTO.getParentId() != null ? menuDTO.getParentId() : 0)
                .ne(Menu::getId, menuDTO.getId());
        if (menuMapper.selectCount(wrapper) > 0) {
            throw new BusinessException("同级菜单名称已存在");
        }

        // 更新菜单
        Menu menu = new Menu();
        BeanUtils.copyProperties(menuDTO, menu);
        menu.setUpdatedAt(LocalDateTime.now());

        return menuMapper.updateById(menu) > 0;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean deleteMenu(Long id) {
        // 检查菜单是否存在
        Menu menu = menuMapper.selectById(id);
        if (menu == null) {
            throw new BusinessException("菜单不存在");
        }

        // 检查是否有子菜单
        LambdaQueryWrapper<Menu> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(Menu::getParentId, id);
        if (menuMapper.selectCount(wrapper) > 0) {
            throw new BusinessException("存在子菜单，无法删除");
        }

        // 删除角色菜单关联
        roleMenuMapper.deleteByMenuId(id);

        // 删除菜单
        return menuMapper.deleteById(id) > 0;
    }

    @Override
    public List<MenuDTO> getMenuTreeByRoleId(Integer roleId) {
        // 获取角色菜单列表
        List<Menu> menuList = menuMapper.selectMenusByRoleId(roleId);
        // 转换为DTO
        List<MenuDTO> menuDTOList = menuList.stream().map(this::convertToDTO).collect(Collectors.toList());
        // 构建菜单树
        return buildMenuTree(menuDTOList);
    }

    @Override
    public List<Long> getMenuIdsByRoleId(Integer roleId) {
        return menuMapper.selectMenuIdsByRoleId(roleId);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean assignRoleMenus(Integer roleId, List<Long> menuIds) {
        // 删除原有角色菜单关联
        roleMenuMapper.deleteByRoleId(roleId);

        // 如果菜单ID列表为空，则直接返回成功
        if (menuIds == null || menuIds.isEmpty()) {
            return true;
        }

        // 批量插入角色菜单关联
        return roleMenuMapper.batchInsert(roleId, menuIds) > 0;
    }

    /**
     * 将实体转换为DTO
     *
     * @param menu 菜单实体
     * @return 菜单DTO
     */
    private MenuDTO convertToDTO(Menu menu) {
        MenuDTO dto = new MenuDTO();
        BeanUtils.copyProperties(menu, dto);
        return dto;
    }

    /**
     * 构建菜单树
     *
     * @param menuList 菜单列表
     * @return 菜单树
     */
    private List<MenuDTO> buildMenuTree(List<MenuDTO> menuList) {
        // 按照父级ID分组
        Map<Long, List<MenuDTO>> parentMap = menuList.stream()
                .collect(Collectors.groupingBy(MenuDTO::getParentId));

        // 获取顶级菜单
        List<MenuDTO> rootMenus = parentMap.getOrDefault(0L, new ArrayList<>());

        // 递归设置子菜单
        rootMenus.forEach(menu -> setChildren(menu, parentMap));

        return rootMenus;
    }

    /**
     * 递归设置子菜单
     *
     * @param menu 当前菜单
     * @param parentMap 父级菜单映射
     */
    private void setChildren(MenuDTO menu, Map<Long, List<MenuDTO>> parentMap) {
        List<MenuDTO> children = parentMap.getOrDefault(menu.getId(), new ArrayList<>());
        menu.setChildren(children);
        children.forEach(child -> setChildren(child, parentMap));
    }

    /**
     * 获取子菜单ID列表
     *
     * @param menuId 菜单ID
     * @return 子菜单ID列表
     */
    private List<Long> getChildMenuIds(Long menuId) {
        List<Long> childIds = new ArrayList<>();
        // 查询所有菜单
        List<Menu> allMenus = menuMapper.selectList(null);
        // 递归获取子菜单ID
        getChildMenuIdsRecursive(menuId, allMenus, childIds);
        return childIds;
    }

    /**
     * 递归获取子菜单ID
     *
     * @param menuId 菜单ID
     * @param allMenus 所有菜单
     * @param childIds 子菜单ID列表
     */
    private void getChildMenuIdsRecursive(Long menuId, List<Menu> allMenus, List<Long> childIds) {
        allMenus.stream()
                .filter(menu -> menuId.equals(menu.getParentId()))
                .forEach(menu -> {
                    childIds.add(menu.getId());
                    getChildMenuIdsRecursive(menu.getId(), allMenus, childIds);
                });
    }
} 